/**
 * @description 既然变量可以指向函数，函数的参数能接收变量，那么一个函数就可以接收另一个函数作为参数，这种函数就称之为高阶函数。高阶函数就是参数里面带有函数
 */

//#region 高阶函数
/**
 * @function higherOrderFunction 高阶函数
 * @param callback { function } 回调函数
 * @param uniapp { number } 传入的参数(暂不使用)
 * @description 实例
 */
function higherOrderFunction(callback,uniapp) {
    return function() {
        console.log('这是高阶函数的内部函数');
        callback("这是回调函数");
    };
}

function mycallback(e){
    console.log(e)
}

//函数调用方法可以直接放在“（）”内容 不用写mycallback() 此函数为高阶函数
const newFunction = higherOrderFunction(mycallback);

newFunction();
//#endregion


//#region 相乘计算
/**
 * @function Multiply 相乘计算
 * @param a { Number } 第一个参数
 * @param b { Number } 第二个参数
 * @param fn { function } 高阶函数方法
 * @description 实例一
 */
function Multiply(a,b,fn){
    return fn(a) + fn(b)
}

function myfn(num){
    return num * 2
}
const result = Multiply(2,3,myfn);
console.log(result) // 10
//#endregion


//#region 平方计算
/**
 * @function Square 平方计算
 * @param power { Number } 平方次数
 * @description 实例二
 */
function Square(power){
    return power * power
}
let SquareArr = [1,2,3,4,5,6];
let resultArr = SquareArr.map(Square) //不需要带参数函数会自己调用
console.log(resultArr) // [1, 4, 9, 16, 25, 36]
//#endregion


//#region 仿造reduce计算
/**
 * @function Reduces 仿造reduce计算
 * @param callback { funciton } 回调函数
 * @description 实例三
*/
function Reduces(callback){
    if(!callback instanceof Function){
        return console.err(callback + "is not defind")
    }
    /**
     * 累加器
     */
    let accumulator = 0;
    for(let i = 0; i < this.length; i++){
        /*
            0 = 0 + 1
            1 = 1 + 2
            3 = 3 + 3
            6 = 6 + 4
            10 = 10 + 5
            15 = 15 + 6 // 21
        */
        accumulator = callback(accumulator,this[i])
    }
    return accumulator
}
Object.prototype.Reduces = Reduces
var arr = [1,2,3,4,5,6]

/**
 * @function fn 累加函数
 * @param pre { Number } 上一个值
 * @param cur { Number } 当前值
 */
const fn = (pre,cur) => pre + cur
let newarr = arr.Reduces(fn) // 21
//#endregion


//#region class继承
/**
 * @description super 关键字用于调用对象的父对象上的函数。只能是函数 不能调用变量 变量可以用this调用 
 */
// 定义一个父类
class Father {
    // 构造函数，接收一个参数name 对象初始化操作
    constructor(name){
        // 将参数name赋值给实例的name属性
        this.name = name
    }
    // 定义一个方法，输出"我是父类"
    getName(){
        console.log("我是父类")
    }
}

// 定义一个子类，继承父类
class Child extends Father {
    
    // 重写父类的方法
    getName(){
        // 输出"我是子类"和实例的name属性
        console.log("我是子类" + this.name)
        // 调用父类的方法
        super.getName()
    }
}

// 创建一个子类的实例，并传入参数"熊肖" {{ 实例对象为子类对象 }}
const child = new Child("熊肖")
// 输出实例
console.log(child)
//#endregion


//#region 闭包
/**
 * @function createCounter 闭包
 * @param callback { String } 回调函数
 * @description 实例四
 * @returns { number } 返回值
 */
function createCounter(callback){
    var count = 0;
    return function(){
        /**
         * ++count 前置递增 返回的是count+1的值
         * count++ 后置递增 先返回count值再加1
         */
        count = callback(++count)
        return count
    }
}

/**
 * @function mycallbacks 操作回调函数
 * @param num { number } 操作数 
 * @returns 
 */
function mycallbacks(num){
    return num
}
var createdFn = createCounter(mycallbacks)
console.log(createdFn()) // 1
console.log(createdFn()) // 2
console.log(createdFn()) // 3

//#endregion


//#region 仿造filter
/**
 * @function filters 仿造filter
 * @param callback { function } 回调函数
 * @description 实例五
 */
function filters(callback){
    if(typeof(callback) != "function"){
        return console.err(callback + "is not defind")
    }
    let arr = []
    for(var i = 0;i<this.length;i++){
        if(callback(this[i],i)){
            arr.push(this[i])
        }
    }
    return arr
}
Object.prototype.filters = filters
/**
 * @function myfilter 函数
 * @param item { Object } 当前值
 * @param index { Number } 当前索引
 */

const myfilter = (item) => item > 3

let arrFilter = arr.filters(myfilter)
console.log(arrFilter) // [4,5,6]

//#endregion


//#region 仿造map
function maps(callback){
    if(typeof(callback) != "function"){
        return console.err(callback + "is not defind")
    }
    let arr = []
    for(var i = 0;i<this.length;i++){
        /**
         * 1 * 2 = 2
         * 2 * 2 = 4
         * 3 * 2 = 6
         * 4 * 2 = 8
         * 5 * 2 = 10
         * 6 * 2 = 12
         * 7 * 2 = 14
         * 8 * 2 = 16
         * 9 * 2 = 18
         * 10 * 2 = 20
         * 回调函数只会返回一个计算后的值
         */
        arr.push(callback(this[i],i))
    }
    return arr
}
Object.prototype.maps = maps
const mymap = (item) => item * 2

let arrMap = arr.maps(mymap)
console.log(arrMap) // [2,4,6,8,10,12,14,16,18,20]

//#endregion


//#region 仿造every
/**
 * @function every 仿造every
 * @param callback { function } 回调函数
 * @description 实例六
 */
function every(callback){
    if(Object.prototype.toString.call(callback) != "[object Function]"){
        return console.err(callback + "is not defind")
    }
    for(var i = 0;i<this.length;i++){
        if(this[i] != callback(this[i],i)){
            return false
        }else{
            return true
        }
    }
}
Object.prototype.every = every

const myevery = (item) => item > 2
let arrEvery = arr.every(myevery)
console.log(arrEvery) // true

//#endregion


//#region 仿造some
/**
 * @function some 仿造some
 * @param callback { function } 回调函数
 * @description 实例七
 */
function some(callback){
    if(Object.prototype.toString.call(callback) != "[object Function]"){
        return console.err(callback + "is not defind")
    }
    for(var i = 0;i<this.length;i++){
        if(this[i] == callback(this[i],i)){
            return true
        }else{
            return false
        }
    }
}
Object.prototype.some = some

const mysome = (item) => item > 2
let arrSome = arr.some(mysome)
console.log(arrSome) // true
//#endregion


//#region 仿造indexOf

/**
 * @function indexOf 仿造indexOf
 * @param Number { number } 参数
 * @description 实例八
 */
function indexOf(Number){
    if(Object.prototype.toString.call(Number) != "[object Number]"){
        return console.err(Number + "is not defind")
    }
    if(this.length == 0){
        return console.err("indexOf is not defind")
    }
    for(var i = 0;i<this.length;i++){
        if(this[i] == Number){
            return i
        }else{
            return -1
        }
    }
}
Object.prototype.indexOf = indexOf

let arrIndexOf = arr.indexOf(1)
console.log(arrIndexOf) // 0

//#endregion


//#region 仿造findIndex
/**
 * @function findIndex 仿造findIndex
 * @param callback { function } 回调函数
 * @description 实例九
 */

function findIndex(callback){
    if(Object.prototype.toString.call(callback) != "[object Function]"){
        return console.err(callback + "is not defind")
    }
    for(let i = 0;i<this.length;i++){
        if(callback(this[i],i)){
            return i
        }else{
            return -1
        }
    }
}
Object.prototype.findIndex = findIndex

const myfindIndex = (item) => item < 5
//myfindIndex 映射的是函数（相当于返回的是function） myfindIndex() 才是函数的执行结果（return的是函数的返回结果）
let arrFindIndex = arr.findIndex(myfindIndex)
console.log(arrFindIndex) // 0


//#endregion


//#region 切面编程

function say(who) {
    console.log(who + '：函数执行了');
}
Function.prototype.before = function(callback) { //before 返回的是一个函数
    return (...args) => {
        callback() // 你要被调用了
        this(...args)
    }
}
let whoSay = say.before(function() {
    console.log('你要被调用了');
})
console.log(whoSay)
whoSay('ljc')

//#endregion


//#region return函数
const Fn = () => {
    var that = "this is ok";
    return (that)=>{
        console.log(that)
    }
}
Fn()("this is ok") // this is ok

//#endregion


//#region 静态类

class StaticClass {
    constructor(){
        this.name = "111"
        console.log(this)
    }
    static say(){
        return true
    }
    uniapp(){
        StaticClass.say()
    }
}
console.log(StaticClass.say()) // true

//#endregion


//#region 仿造slice

function slice(start,end){
    if(Object.prototype.toString.call(start) != "[object Number]"){
        return console.err(start + "is not defind")
    }
    if(Object.prototype.toString.call(end) != "[object Number]"){
        return console.err(end + "is not defind")
    }
    let arr = [];
    for(var i = 0;i<this.length;i++){
        if(i < end && i >= start){
            arr.push(this[i])
        }
    }
    return arr;
}

Array.prototype.slice = slice

let arrSlice = [1,2,3,4,5].slice(1,3)
console.log(arrSlice) // [2,3]

//#endregion